home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
X User Tools
/
X User Tools (O'Reilly and Associates)(1994).ISO
/
sources
/
xbmbrows
/
xbmbro31.z
/
xbmbro31
/
xbmbrowser3.1
/
bitmaps.c
next >
Wrap
C/C++ Source or Header
|
1993-08-05
|
14KB
|
437 lines
/********************************************************************\
** _________________________________ **
** A n t h o n y |________ __ __ _________| **
** | |o_| |o_| | **
** T h y s s e n __| __ __ |__ **
** __| __| | | |__ |__ **
** `` Dragon Computing! '' __| __| | | |__ |__ **
** |_____| |__| |_____| **
** **
\********************************************************************/
/*
** bitmap.c
**
** This module represents a complete re-write of the data structures used
** by xbmbrowser to orginise the bitmaps and widgets. These structures
** although initially created in get_files(), are static to this module.
** Previously the data structure did not allow for expandsion of bitmap
** types, storage of pixel colors used, or for checks on modification
** times.
** Anthony Thyssen <anthony@dragon.cit.gu.edu.au>
*/
#include "xbmbrowser.h"
static Item *new_file_list = NULL; /* new file list for merging */
static Item *file_list = NULL; /* current list of files (& dir) */
static Widget *widget_array = NULL; /* array of widgets available to use */
static int allocated = 0; /* number of widgets in above array */
static int managed = 0; /* number of widgets being managed */
static int file_counts[(int)NumFileTypes]; /* count of the various file types */
/*--------------------------------------------------------------------------*/
build_dirMenu()
/* Build the dirMenu from the just read in filelist. It is in this module
** only because it doesn't seem to fit in other modules.
*/
{
static char *list[256];
int list_offset = 0;
Item *item = new_file_list;
list[list_offset++] = "/";
list[list_offset++] = "~/";
/* add to the menu any name in the file list that is a directory */
while( item != NULL ) {
if( item->type == Dir )
list[list_offset++] = item->fname;
item = item->next;
}
list[list_offset] = NULL;
XtVaSetValues(dirList,XtNdefaultColumns,(XtArgVal)(list_offset/25)+1,NULL);
XawListChange(dirList,list,0,0,True);
}
/*--------------------------------------------------------------------------*/
Item *
alloc_item()
/* allocate and default a file item */
{
Item *item = (Item *) malloc( sizeof(Item) );
item->fname[0] = '\0';
item->type = Bad;
item->bitmap = None;
item->index = -1;
item->next = NULL;
return item;
}
Item *
free_item(item)
/* free the item and any aspect about that item. This is the ONLY place
** where bitmaps are to be freed. Return the next item in list!
*/
Item *item;
{
Item *next = item->next;
if( item->bitmap != None ) { /* bitmap to be freed ? */
if( item->index != -1 ) {
/* remove from bitmap from widget
** NOTE: for some reason if the bitmap used by the widget is
** set to `None', the XFreePixmap following will coredump!
*/
XtVaSetValues(widget_array[item->index],
XtNbitmap, (XtArgVal)None, /* None */
XtNlabel, (XtArgVal)NULL, NULL);
}
XFreePixmap(XtDisplay(toplevel), item->bitmap );
#ifdef DO_XPMS
if( item->type == Xpm ) {
/* free colors and attributes used by pixmap */
/* PROBLEM -- what if color is used by another pixmap ? */
#if 0
XFreeColors(XtDisplay(toplevel),
DefaultColormapOfScreen(XtScreen(toplevel)),
item->attr.pixels, item->attr.npixels, AllPlanes);
#endif
XpmFreeAttributes((XpmAttributes *)&item->attr);
}
#endif
}
free( item );
return next;
}
static int
read_bitmap(item)
/* attempt to read a bitmap for the item given -- return TRUE if success */
Item *item;
{
int i, status; /* junk integer, size of icon, return status */
unsigned int x, y;
#ifdef DO_XPMS
Pixmap m; /* junk pixmap mask */
#endif
if( item->type != File ) /* if a not a file -- it can't be a bitmap */
return FALSE;
/* first try for a X Bitmap file format */
status = XReadBitmapFile(XtDisplay(toplevel),
DefaultRootWindow(XtDisplay(toplevel)),
item->fname, &x, &y, &item->bitmap, &i, &i);
if( status == BitmapSuccess ) {
item->type = Xbm;
(void) sprintf(item->info, "\"%s\", %dx%d bitmap", item->fname, x, y);
return TRUE;
}
#ifdef DO_XPMS
/* Try a X Pixmap format */
item->attr.valuemask = XpmReturnPixels | XpmCloseness;
status = XpmReadPixmapFile(XtDisplay(toplevel),
DefaultRootWindow(XtDisplay(toplevel)),
item->fname, &item->bitmap,&m,&item->attr);
switch( status ) {
case XpmSuccess:
item->type = Xpm;
(void) sprintf(item->info, "\"%s\", %dx%d pixmap (%d colors)",
item->fname, item->attr.width, item->attr.height,
item->attr.npixels);
if ( m != None )
XFreePixmap(XtDisplay(toplevel), m);
return TRUE;
case XpmColorFailed:
case XpmNoMemory:
item->type = BadXpm;
if ( item->bitmap != None ) {
XFreePixmap(XtDisplay(toplevel), item->bitmap);
item->bitmap = None;
}
if ( m != None )
XFreePixmap(XtDisplay(toplevel), m);
return FALSE;
}
#endif
/* Non Bitmap file */
item->type = File; /* unknown plain file -- can't tell */
item->bitmap = None;
return 0;
}
void
free_list(list)
Item **list; /* pointer to a list pointer */
/* completely free all items in the given item list */
{
while( *list != NULL )
*list = free_item( *list );
}
void
set_label_info()
/* set the contents of the label widgets information string from the
** current values of the file type counts. NOTE: watch the string length!
*/
{
# define strend label_info+strlen(label_info)
label_info[0] = '\0'; /* empty the string */
if( file_counts[Xbm] > 0 )
sprintf(strend, " %d Bitmaps ", file_counts[Xbm] );
if( file_counts[Xpm] > 0 )
sprintf(strend, " %d Pixmaps ", file_counts[Xpm] );
if( file_counts[BadXpm] > 0 )
sprintf(strend, " %d Can't Show ", file_counts[BadXpm] );
if( file_counts[File] + file_counts[Bad] > 0 )
sprintf(strend, " %d Unknown ", file_counts[File] + file_counts[Bad] );
if( file_counts[Dir]-2 > 0 )
sprintf(strend, " %d Dirs ", file_counts[Dir]-2 );
XtVaSetValues(lw, XtNlabel, (XtArgVal)label_info, NULL);
# undef strend
}
/*------------------------------------------------------------------------*/
static void
allocate_widgets( n )
/* create enough widgets to display n bitmaps */
int n;
{
char name[8];
Widget w;
if( allocated == n ) return; /* just right -- no need to do anthing */
if( allocated < n ) { /* ok allocate more widgets */
if(widget_array == NULL) {
widget_array = (Widget *)malloc( n * sizeof(Widget) );
if( widget_array == NULL ) {
perror("xbmbrowser: malloc widget_array");
abort();
}
} else {
widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
if( widget_array == NULL ) {
perror("xbmbrowser: realloc larger widget_array");
abort();
}
}
for( ; allocated < n; allocated++ ) {
sprintf(name, "%d", allocated);
w = XtVaCreateWidget(name, labelWidgetClass, bw, NULL);
XtOverrideTranslations(w, XtParseTranslationTable(Translations));
widget_array[allocated] = w;
}
}
#if 0
/* This code will eventually cause a core dump when lots of directory
** changes are performed by the user. The problem seems to occur when
** widgets are really destroyed (they are just flaged for destruction
** below. I can't seem to find any problem with the code below however.
** It just doesn't seem to work.
*/
else { /* ok we have too many widgets -- remove about a 1/3 of them */
n = ( allocated + allocated + n ) / 3; /* the final level we want */
for( allocated--; allocated >= n ; allocated-- )
XtDestroyWidget( widget_array[allocated] );
allocated++;
widget_array = (Widget *)realloc(widget_array, n * sizeof(Widget) );
if( widget_array == NULL ) {
perror("xbmbrowser: realloc smaller widget_array");
abort();
}
}
/* insure that allocated is now equal to n (which may be calculated above */
assert( allocated == n );
#endif
}
static void
merge_bitmaps()
/* Merge the old_file_list that is currently with the new_file_list just
** read in. Adjust the new list to reflect any changes to the current
** directory looking for additions, deletions and modifications to the
** bitmap files.
*/
{
Item *old_file_list; /* the old file list that we originally had */
Item **last_ptr; /* pointer to the last ponter in the merged list */
Item *item; /* general item pointer */
int count, cmp; /* count of bitmaps, filename comparasion */
/* first un-manage all the widgets and free the current file_list
** This saves on multiple geometry requests while we do the work
*/
if( managed > 0 ) {
XtUnmanageChildren(widget_array, managed);
managed = 0;
}
old_file_list = file_list; /* make the current list old */
file_list = NULL; /* file list (the merger) is empty */
last_ptr = &file_list; /* point to the last pointer in empty list */
/* zero all the file_type counts */
for( count = 0 ; count < NumFileTypes ; count++ )
file_counts[count] = 0;
count = 0; /* count of widgets with valid bitmaps */
while( old_file_list != NULL && new_file_list != NULL ) {
/* items present in both lists */
cmp = strcmp( old_file_list->fname, new_file_list->fname );
if( cmp == 0 ) {
if ( old_file_list->mtime == new_file_list->mtime ) {
/* NO CHANGE -- same file in both lists without any modifications */
new_file_list = free_item( new_file_list ); /* junk the new item */
*last_ptr = item = old_file_list; /* append old item to merged list */
last_ptr = &(item->next); /* adjust last_ptr in merged list */
old_file_list = *last_ptr; /* remove item from old list */
/* *last_ptr = NULL; /* not really nessary */
/* adjust the counts of the file types */
if( item-> bitmap != None ) count++;
file_counts[item->type]++;
continue;
}
else {
/* MODIFIED -- same file but it has been modified or replaced */
old_file_list = free_item( old_file_list ); /* junk the old item */
cmp = 1; /* ok now pretend that the new item is a new addition */
/* FALL THROUGH */
}
}
/* ADDITION -- a new file (or newly modified) to be added to list */
if( cmp > 0 ) {
/* a new file added to the directory -- append it to file_list */
*last_ptr = item = new_file_list; /* append new item to merged list */
last_ptr = &(item->next); /* adjust last_ptr in merged list */
new_file_list = *last_ptr; /* remove item from new list */
/* *last_ptr = NULL; /* not really nessary */
if( item->type == File && read_bitmap( item ) ) /* read in bitmap */
count++; /* count number of valid bitmaps */
file_counts[item->type]++; /* count up the file types */
continue;
}
/* DELETION -- the old file has been deleted */
if( cmp < 0 ) {
old_file_list = free_item( old_file_list ); /* delete this file */
continue;
}
/* this point should never be reached */
/*NOTREACHED*/
assert( FALSE );
}
/* --------------
** At this point either one or both of the merging file lists
** is empty. As such we can just finish of the merged list quickly
*/
assert( new_file_list == NULL || old_file_list == NULL );
/* ADD any more new files in the new_file_list */
*last_ptr = new_file_list; /* the rest of the merged list is new */
for( item = new_file_list; item != NULL; item = item->next ) {
if( item->type == File && read_bitmap( item ) )
count++;
file_counts[item->type]++;
}
new_file_list = NULL; /* new_file_list is now empty */
/* DELETE any old items left in the old_file_list */
free_list(&old_file_list);
/* --------------
** Merger of file lists complete. Allocate enough widgets to
** hold the bitmaps to be displayed and display them.
*/
/* allocate/deallocate widgets as needed */
allocate_widgets( count );
/* assign the bitmaps to the widgets in order */
managed = 0; /* this should be zero but make sure */
for( item = file_list; item != NULL; item = item->next )
if( item->bitmap != None ) {
item->index = managed;
XtVaSetValues( widget_array[item->index],
XtNbitmap, (XtArgVal)item->bitmap,
XtNlabel, (XtArgVal)item->info, NULL);
managed++;
}
/* check the result */
assert( managed == count );
/* manage the widgets */
if( managed > 0 )
XtManageChildren(widget_array, managed);
}
/*------------------------------------------------------------------------*/
void
scan_bitmaps()
/* scan and display all the bitmaps in the current directory */
{
/* just free all the bitmaps and do a rescan which handles the
** reading of new bitmaps perfectly fine on its own. We need
** to unmanage them here, to avoid problems.
*/
if( managed > 0 ) {
XtUnmanageChildren(widget_array, managed);
managed = 0;
}
free_list(&file_list);
rescan_bitmaps();
}
void
rescan_bitmaps()
/* Do a fast rescan and merger of the bitmaps in the current directory.
** The goal is to avoid re-reading files which were never changed.
*/
{
assert( new_file_list == NULL );
new_file_list = get_files("."); /* the items in the current directory */
build_dirMenu(); /* build the directory menu from new list */
merge_bitmaps(); /* merge any changes into file_list */
set_label_info(); /* show the file counts being displayed */
if( new_file_list != NULL ) {
fprintf(stderr, "xbmbrowser: bad new_file_list in rescan_bitmaps\n");
abort();
}
}